﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Galoap
{
    abstract partial class Answer
    {
        
        /// <summary>
        /// method which gets an answer updating DB: it creates a new answer if there aren't or updates the answer count otherwhise
        /// it recognizes if it's a "no" answer
        /// </summary>
        /// <typeparam name="T">the type of the answer to made</typeparam>
        /// <param name="question">the question which is relative to this answer</param>
        /// <param name="gameSession">the gamesession that is responding</param>
        /// <param name="answer">the answer given</param>
        /// <param name="confirm">a bool that, if false, indicates that is a "no" answer, true otherwise</param>
        /// <returns>the answer saved on database</returns>
        public static T CreateAnswer<T>(Question question, GameSession gameSession, String answer, bool confirm) where T : Answer, new()
        {
            // checks if confirm is true, in this case it's a "yes" answer or a generic answer
            // otherwise it's a "no" answer and it can decrease answer counter
            if (confirm)
                return CreateAnswer<T>(question, gameSession, answer);
            else
            {
                T retAnswer = new T();
                retAnswer.Initialize(answer);
                question.Answer.Load();

                // check for user ranking
                bool isknown = false;

                try {
                    IEnumerable<T> listOfAnswers = question.Answer.OfType<T>().ToList<T>();
                    // verify if there are a Truth answer (answer given by game programmer to prevent cheating)
                    foreach (Answer a in listOfAnswers)
                    {
                        isknown = isknown || a.Truth;
                    }
                    retAnswer = listOfAnswers.Where(a => a.CompareData(retAnswer)).First();
                    retAnswer.Counter--;
                }
                catch (InvalidOperationException e)
                {
                    Console.Error.WriteLine(e.Message);
                }

                // update user ranking
                gameSession.UpdateUserRanking(retAnswer, isknown);
                gameSession.Add(retAnswer);
                return retAnswer;
            }

        } 

        /// <summary>
        /// method which gets an answer updating DB: it creates a new answer if there aren't or updates the answer count otherwhise
        /// </summary>
        /// <typeparam name="T">the type of the answer to made</typeparam>
        /// <param name="question">the question which is relative to this answer</param>
        /// <param name="gameSession">the gamesession that is responding</param>
        /// <param name="answer">the answer given</param>
        /// <returns>the answer saved on database</returns>
        public static T CreateAnswer<T>(Question question, GameSession gameSession, object answer) where T : Answer, new()
        {
            T retAnswer = new T();
            retAnswer.Serialize(answer);
            question.Answer.Load();

            try
            {
                retAnswer = question.Answer.OfType<T>().Where(a => a.CompareData(retAnswer)).First();
            }
            catch (InvalidOperationException)
            {
                retAnswer.Counter = 1;
                GaloapDatabase.Database.AddToAnswer(retAnswer);
                question.Answer.Add(retAnswer);
            }

            gameSession.Add(retAnswer);
            return retAnswer;
        }

        /// <summary>
        /// method which create a string representation of the answer
        /// </summary>
        /// <returns>the string representing the answer</returns>
        public abstract override string ToString();

        /// <summary>
        /// method which compare data of two different questions
        /// </summary>
        /// <param name="a">the answer that will be compared with this</param>
        /// <returns>true if the data is the same data, false otherwise</returns>
        public abstract bool CompareData(Answer a);

        /// <summary>
        /// methods which serialize an object in a string
        /// </summary>
        /// <param name="o">the object to serialize</param>
        virtual public void Serialize(object o)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// This method converts the object serialized in the corrispective list of ontologies.
        /// This should be used for post elaboration of the knowledge collected by this games.
        /// </summary>
        /// <returns>the object saved in the serialized answer s</returns>
        virtual public object Deserialize()
        {
            throw new NotImplementedException();
        }
    }
}
